/*
 * PS3Controller.h
 *
 *  Created on: Jan 24, 2015
 *      Author: mhealy
 */

#ifndef PS3CONTROLLER_H_
#define PS3CONTROLLER_H_

#include <iostream>
#include <string>
#include <vector>

#define PS3_CONTROLLER_BUTTONS \
	PS3_CONTROLLER_BUTTON(Triangle) \
	PS3_CONTROLLER_BUTTON(Circle) \
	PS3_CONTROLLER_BUTTON(Cross) \
	PS3_CONTROLLER_BUTTON(Square) \
	PS3_CONTROLLER_BUTTON(Left1) \
	PS3_CONTROLLER_BUTTON(Right1) \
	PS3_CONTROLLER_BUTTON(Left2) \
	PS3_CONTROLLER_BUTTON(Right2) \
	PS3_CONTROLLER_BUTTON(Select) \
	PS3_CONTROLLER_BUTTON(Start) \
	PS3_CONTROLLER_BUTTON(LeftStick) \
	PS3_CONTROLLER_BUTTON(RightStick) \

class Joystick;
class JoystickButton;

class PS3Controller {
public:
	PS3Controller(Joystick* stick);
	virtual ~PS3Controller();

	enum Button {
#define PS3_CONTROLLER_BUTTON(x)	x,
		PS3_CONTROLLER_BUTTONS
#undef PS3_CONTROLLER_BUTTON
		NumButtons
	};

	bool isButtonDown(Button b);
	unsigned int getNumButtons() const {
		return NumButtons;
	}
	const std::string& getButtonName(Button b) const {
		return buttonNames_[b];
	}
	Joystick* getStick() {
		return stick_;
	}
private:
	Joystick* const stick_;
	std::vector<JoystickButton*> buttons_;
	static const std::string buttonNames_[NumButtons];
};

template <typename T>
class ControllerMonitor {
private:
	T& controller_;
	std::vector<bool> buttons_;
public:
	ControllerMonitor(T & controller) : controller_(controller) {
		buttons_.resize(controller_.getNumButtons());
	}
	void strobe() {
		bool changed = false;
		for (unsigned int i = 0; i < buttons_.size(); ++i) {
			typename T::Button button = static_cast<typename T::Button>(i);
			const bool value = controller_.isButtonDown(button);
			if (buttons_[i] != value) {
				changed = true;
				std::cout << controller_.getButtonName(button)
						  << (value ? "down" : "up")
						  << ' ';
			}
			buttons_[i] = value;
		}
		if (changed) {
			std::cout << std::endl;
		}
	}
	Joystick* getStick() {
		return controller_.getStick();
	}
private:
};

#endif /* PS3CONTROLLER_H_ */
